<template>
  <swiper :options="swiperConfig" ref="swiper">
    <swiper-slide v-for="({year, month}, index) in monthList">
      <Calendar-slide
        :year="year"
        :month="month"
        :index="index"
        :dateList="dateList"
        :dateUserSelect="dateUserSelect"
        @click="handleClick"
      />
    </swiper-slide>
  </swiper>
</template>

<script>
  /**
   * 日历控件，依赖vue-awesome-swiper
   * 事件：
   *    select({date, valid})         日期切换，date：日期格式化字符，valid：是否在日期列表内
   *    slideChange({year, month})    滑块切换，year：新滑块的年份，month：新滑块的月份
   */
  import {dateFormat} from '../../utils/'
  import CalendarSlide from './calendarSlide.vue'
  import {swiper, swiperSlide} from 'vue-awesome-swiper'

  const _now = new Date();
  const now = {
    date: _now,
    year: _now.getFullYear(),
    month: _now.getMonth() + 1,
    formattedString: dateFormat(_now, 'YYYY-MM-DD')
  };

  export default {
    name: 'calendar',

    components: {
      swiper,
      swiperSlide,
      CalendarSlide
    },

    props: {
      /**
       * 日期列表
       * [{
       *    date, {STRING}       日期格式化字符串
       *    position, {NUMBER}   日期距当前日期的天数，已过日期的position为负
       *    tick, {BOOLEAN}      是否通过
       *  }...]
       */
      dateList: {
        type: Array,
      },

      // 选中的日期,YYYY-MM-DD
      dateUserSelect: {
        type: String,
      }
    },

    data() {
      const vm = this;
      const [year = '', month = ''] = this.dateUserSelect && this.dateUserSelect.split('-') || [];

      return {
        date: {year, month},

        today: '',

        // 每个滑块的年份月份列表，默认为当前月
        monthList: [
          {year: now.year, month: now.month}
        ],

        // 今天是否超出日期范围，用来判断是否可以返回今天
        todayIsOutOfDateList: false,

        // 今天的月份在slide列表中的位置，用来判断初始显示哪个slide
        slideIndexOfToday: 0,
        swiperConfig: {
          on: {
            slideChange() {
              vm.handleSwipe(this.activeIndex)
            }
          }
        },
      }
    },

    computed: {
      dateBegin() {
        const date = this.dateList[0].date || now.formattedString;
        const [year, month] = date.split('-');

        return {year: Number(year), month: Number(month)}
      },

      dateEnd() {
        const length = this.dateList.length;
        const date = !!length && this.dateList[length - 1].date || now.formattedString;
        const [year, month] = date.split('-');

        return {year: Number(year), month: Number(month)}
      }
    },

    watch: {
      dateList(val) {
        this.transformDateList(val)
      }
    },

    methods: {
      transformDateList(dateList) {
        if (!dateList || !dateList.length) {
          return this.$ZCAlert.show({
            title: '活动不存在或已结束！'
          });
        }

        // 计算月份（滑块）列表
        this.monthList = this.createMonthList();

        // 获取当前日期
        dateList.some(({date, position}) => {
          if(position === 0) {
            this.today = date;
            return true
          }
        });

        // 计算并记录当天的slideIndex,用于返回今天
        this.slideIndexOfToday = this.positionOfOneDayInMonthList(this.today);
        this.todayIsOutOfDateList = typeof this.slideIndexOfToday !== 'number';

        // 计算初始选择日期
        const length = dateList.length;
        const initialDate = this.middleDateInThree(
          this.dateUserSelect || this.today,
          dateList[0].date,
          dateList[length - 1].date
        );

        this.initial(initialDate);
      },

      // 选取三个日期中排在中间的那个
      middleDateInThree(date0, date1, date2) {
        let result = [date0, date1, date2];

        result = result.map(date => {
          if(!date){
            return {
              string: '',
              value: Infinity
            }
          }

          const [Y, M, D] = date.split('-');

          return {
            string: date,
            value: Number(Y) * 365 + Number(M) * 31 + Number(D)
          };
        });

        return result.sort((a, b) => a.value - b.value)[1].string
      },

      initial(date) {
        if (!/\d{4}-\d{2}-\d{2}/.test(date)) {
          console.error('calendar error: invalid date---------->' + date);
          date = now.string
        }

        this.handleClick({
          date, valid: true
        });

        // 滑动到初始日期对应的slide，并触发handleSwipe
        const slideIndex = this.positionOfOneDayInMonthList(date);

        if(!!slideIndex){
          this.$nextTick(() => {
            this.redirect(slideIndex);
          });
        } else {
          // 初始日期在第一个slide，需要手动触发handleSwipe
          this.handleSwipe(0)
        }
      },

      createMonthList() {
        const numOfSlider = (this.dateEnd.year - this.dateBegin.year) * 12
          + this.dateEnd.month - this.dateBegin.month + 1;
        const result = [];
        let n = 0, {year: lastYear, month: lastMonth} = this.dateEnd;

        do {
          result.unshift({year: lastYear, month: lastMonth});
          --lastMonth;
          if (lastMonth < 0) {
            lastMonth = 12;
            --lastYear
          }
          n++;
        } while (n < numOfSlider);

        return result
      },

      handleSwipe(index) {
        const {year, month} = this.monthList[index];

        this.date = {year, month};
        this.$emit('slideChange', {year, month})
      },

      backToToday() {
        // 滚动到今日所在的slide
        typeof this.slideIndexOfToday === 'number'
        && this.redirect(this.slideIndexOfToday, 300);

        // 触发点击事件
        this.handleClick({
          date: this.today,
          valid: !this.todayIsOutOfDateList
        })
      },

      /**
       * 找到指定日期在monthList中的位置
       * @param day {string} 格式化日期字符‘YYYY-MM-DD’
       * @returns {*}
       */
      positionOfOneDayInMonthList(day) {
        if(!day) return false;

        let result;
        let [_year, _month] = day.split('-');

        _year = Number(_year);
        _month = Number(_month);
        console.log('today:', _year, _month);
        this.monthList.some(({year, month}, index) => {
          if (year === _year && month === _month) {
            result = index;
            return true
          }
        });

        return result
      },

      handleClick(content) {
        this.$emit('select', content);
        this.$emit('change', content);
      },

      redirect(position, duration = 0) {
        const swiper = this.$refs.swiper.swiper;

        swiper && swiper.slideTo(position, duration, false);
      }
    }
  }
</script>
